﻿using System.Collections;
using System.Utility.System;
using System.Web;
using System.Web.Caching;

namespace System.Data
{
    public static class CacheManager
    {
        private readonly static ICache _CacheService;

        static CacheManager()
        {
            _CacheService = new NetCache();
        }

        public static void AddObject<TInput>(string key, TInput ob, int duration)
        where TInput : class
        {
            _CacheService.Add(key, ob, duration);
        }

        public static void ClearAll()
        {
            _CacheService.ClearAll();
        }

        public static TResult GetCache<TResult>(string key, int duration, Func<TResult> func)
        where TResult : class
        {
            TResult tResult;
            if (_CacheService.Contains(key))
            {
                TResult tResult1 = _CacheService.Get<TResult>(key);
                if (tResult1 != null)
                {
                    tResult = tResult1;
                    return tResult;
                }
            }
            TResult tResult2 = func();
            if (tResult2 != null)
            {
                _CacheService.Add(key, tResult2, duration);
            }
            tResult = tResult2;
            return tResult;
        }

        public static TResult GetCache<T1, TResult>(string key, int duration, Func<T1, TResult> func, T1 arg)
        where TResult : class
        {
            TResult tResult;
            if (_CacheService.Contains(key))
            {
                TResult tResult1 = _CacheService.Get<TResult>(key);
                if (tResult1 != null)
                {
                    tResult = tResult1;
                    return tResult;
                }
            }
            TResult tResult2 = func(arg);
            if (tResult2 != null)
            {
                _CacheService.Add(key, tResult2, duration);
            }
            tResult = tResult2;
            return tResult;
        }

        public static TResult GetCache<T1, T2, TResult>(string key, int duration, Func<T1, T2, TResult> func, T1 arg1, T2 arg2)
        where TResult : class
        {
            TResult tResult;
            if (_CacheService.Contains(key))
            {
                TResult tResult1 = _CacheService.Get<TResult>(key);
                if (tResult1 != null)
                {
                    tResult = tResult1;
                    return tResult;
                }
            }
            TResult tResult2 = func(arg1, arg2);
            if (tResult2 != null)
            {
                _CacheService.Add(key, tResult2, duration);
            }
            tResult = tResult2;
            return tResult;
        }

        public static TResult GetCache<T1, T2, T3, TResult>(string key, int duration, Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3)
        where TResult : class
        {
            TResult tResult;
            if (_CacheService.Contains(key))
            {
                TResult tResult1 = _CacheService.Get<TResult>(key);
                if (tResult1 != null)
                {
                    tResult = tResult1;
                    return tResult;
                }
            }
            TResult tResult2 = func(arg1, arg2, arg3);
            if (tResult2 != null)
            {
                _CacheService.Add(key, tResult2, duration);
            }
            tResult = tResult2;
            return tResult;
        }

        public static TResult GetObject<TResult>(string key)
        where TResult : class
        {
            TResult tResult;
            tResult = (!_CacheService.Contains(key) ? default(TResult) : _CacheService.Get<TResult>(key));
            return tResult;
        }

        public static void Remove(string key)
        {
            if (!string.IsNullOrEmpty(key))
            {
                if (_CacheService.Contains(key))
                {
                    _CacheService.Remove(key);
                }
            }
        }

        public static void Update<TInput>(string key, TInput ob, int duration)
        where TInput : class
        {
            if (!TypeExtension.IsInvalid(key))
            {
                if (_CacheService.Contains(key))
                {
                    _CacheService.Remove(key);
                    AddObject<TInput>(key, ob, duration);
                }
            }
        }
    }



    internal class NetCache : BaseCache
    {
        public NetCache()
        {
        }

        protected override void AddCache(string key, object target, int time, CacheDependency dependency)
        {
            if (HttpContext.Current != null)
            {
                AddCache_BS(key, target, time, dependency);
            }
            else
            {
                AddCache_CS(key, target, time, dependency);
            }
        }

        private void AddCache_BS(string key, object target, int time, CacheDependency dependency)
        {
            if (dependency != null)
            {
                HttpContext.Current.Cache.Insert(key, target, dependency, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
            }
            else
            {
                Cache cache = HttpContext.Current.Cache;
                DateTime now = DateTime.Now;
                cache.Insert(key, target, null, now.AddSeconds((double)time), Cache.NoSlidingExpiration);
            }
        }

        private void AddCache_CS(string key, object target, int time, CacheDependency dependency)
        {
            if (dependency != null)
            {
                HttpRuntime.Cache.Insert(key, target, dependency, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
            }
            else
            {
                Cache cache = HttpRuntime.Cache;
                DateTime now = DateTime.Now;
                cache.Insert(key, target, null, now.AddSeconds((double)time), Cache.NoSlidingExpiration);
            }
        }

        public override void ClearAll()
        {
            IDictionaryEnumerator enumerator;
            if (HttpContext.Current != null)
            {
                enumerator = HttpContext.Current.Cache.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    HttpContext.Current.Cache.Remove(enumerator.Key.ToString());
                }
            }
            else
            {
                enumerator = HttpRuntime.Cache.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    HttpRuntime.Cache.Remove(enumerator.Key.ToString());
                }
            }
        }

        public override bool ContainsKey(string key)
        {
            bool flag;
            if (HttpContext.Current != null)
            {
                flag = (HttpContext.Current.Cache.Get(key) == null ? false : true);
            }
            else
            {
                flag = (HttpRuntime.Cache.Get(key) == null ? false : true);
            }
            return flag;
        }

        protected override T GetCache<T>(string key)
        {
            T t;
            t = (HttpContext.Current != null ? (T)(HttpContext.Current.Cache.Get(key) as T) : (T)(HttpRuntime.Cache.Get(key) as T));
            return t;
        }

        protected override void RemoveCache(string key)
        {
            if (HttpContext.Current == null)
            {
                HttpRuntime.Cache.Remove(key);
            }
            HttpContext.Current.Cache.Remove(key);
        }
    }

    internal abstract class BaseCache : ICache
    {
        private int _time;

        private string _dependencyFilePath;

        public string DependencyFilePath
        {
            get
            {
                return _dependencyFilePath;
            }
            set
            {
                _dependencyFilePath = value;
            }
        }

        public int ExpirationHours
        {
            get
            {
                return _time / 60 / 60;
            }
            set
            {
                _time = value * 60 * 60;
            }
        }

        public int ExpirationMinutes
        {
            get
            {
                return _time / 60;
            }
            set
            {
                _time = value * 60;
            }
        }

        public int ExpirationSenconds
        {
            get
            {
                return _time;
            }
            set
            {
                _time = value;
            }
        }

        public BaseCache()
        {
            _time = 3600;
            _dependencyFilePath = null;
        }

        public void Add(string key, object target, int time)
        {
            if ((string.IsNullOrEmpty(key) ? false : target != null))
            {
                key = key.Trim().ToLower();
                if (!string.IsNullOrEmpty(_dependencyFilePath))
                {
                    AddCache(key, target, time, new CacheDependency(_dependencyFilePath));
                }
                else
                {
                    AddCache(key, target, time, null);
                }
            }
        }

        protected abstract void AddCache(string key, object target, int time, CacheDependency dependency);

        public abstract void ClearAll();

        public bool Contains(string key)
        {
            bool flag;
            if (!string.IsNullOrEmpty(key))
            {
                key = key.Trim().ToLower();
                flag = ContainsKey(key);
            }
            else
            {
                flag = false;
            }
            return flag;
        }

        public abstract bool ContainsKey(string key);

        public T Get<T>(string key)
        where T : class
        {
            T cache;
            if (!string.IsNullOrEmpty(key))
            {
                key = key.Trim().ToLower();
                cache = GetCache<T>(key);
            }
            else
            {
                cache = default(T);
            }
            return cache;
        }

        protected abstract T GetCache<T>(string key)
        where T : class;

        public void Remove(string key)
        {
            if (!string.IsNullOrEmpty(key))
            {
                key = key.Trim().ToLower();
                RemoveCache(key);
            }
        }

        protected abstract void RemoveCache(string key);
    }

    public interface ICache
    {
        string DependencyFilePath
        {
            get;
            set;
        }

        int ExpirationHours
        {
            get;
            set;
        }

        int ExpirationMinutes
        {
            get;
            set;
        }

        int ExpirationSenconds
        {
            get;
            set;
        }

        void Add(string key, object target, int time);

        void ClearAll();

        bool Contains(string key);

        T Get<T>(string key)
        where T : class;

        void Remove(string key);
    }
}